package com.ouyunc.user.service.impl;

import cn.hutool.crypto.SmUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ouyunc.cache.redis.RedisFactory;
import com.ouyunc.common.constant.CommonConstant;
import com.ouyunc.common.utils.SnowflakeUtil;
import com.ouyunc.im.base.LoginUserInfo;
import com.ouyunc.im.constant.CacheConstant;
import com.ouyunc.im.constant.IMConstant;
import com.ouyunc.im.constant.enums.MessageContentEnum;
import com.ouyunc.im.constant.enums.MessageEnum;
import com.ouyunc.im.constant.enums.OnlineEnum;
import com.ouyunc.im.domain.*;
import com.ouyunc.im.domain.bo.ImBlacklistBO;
import com.ouyunc.im.domain.bo.ImFriendBO;
import com.ouyunc.im.domain.bo.ImGroupUserBO;
import com.ouyunc.im.packet.Packet;
import com.ouyunc.im.packet.message.Message;
import com.ouyunc.im.packet.message.content.GroupRequestContent;
import com.ouyunc.im.utils.IdentityUtil;
import com.ouyunc.service.dto.UserDTO;
import com.ouyunc.user.entity.dto.*;
import com.ouyunc.user.mapper.*;
import com.ouyunc.user.service.ImUserService;
import com.ouyunc.web.exception.CustomerException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author fzx
 * im 用户相关
 */
@Service
public class ImUserServiceImpl extends ServiceImpl<ImUserMapper, ImUser> implements ImUserService {

    @Resource
    private ImUserMapper imUserMapper;

    @Resource
    private ImGroupMapper imGroupMapper;

    @Resource
    private ImGroupUserMapper imGroupUserMapper;

    @Resource
    private ImFriendMapper imFriendMapper;

    @Resource
    private ImBlacklistMapper imBlacklistMapper;

    /**
     * 注册im用户
     * @param imUserDTO
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public void register(ImUserDTO imUserDTO) {
        // 校验参数
        Assert.notNull(imUserDTO, "非法参数!");
        Assert.notNull(imUserDTO.getPhoneNum(), "非法参数: phoneNum!");
        Assert.notNull(imUserDTO.getNickName(), "非法参数: nickName!");
        Assert.notNull(imUserDTO.getPassword(), "非法参数: password!");
        // 校验手机号是否存在
        QueryWrapper<ImUser> imUserQueryWrapper = new QueryWrapper<>();
        imUserQueryWrapper.eq("phone_num", imUserDTO.getPhoneNum());
        ImUser exitImUser = getOne(imUserQueryWrapper);
        Assert.isNull(exitImUser, "手机号已被使用，请更换其他手机号！");
        String nowDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        ImUser imUser = new ImUser(null, SnowflakeUtil.nextIdStr(), null, SmUtil.sm3(String.valueOf(imUserDTO.getPassword())), imUserDTO.getNickName(), null, imUserDTO.getPhoneNum(), null, "https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/460d46d0-4fcc-11eb-8ff1-d5dcf8779628.png", null, null, 2, 0, nowDateTime, nowDateTime);
        save(imUser);
    }

    /**
     * 根据唯一用户名获取用户信息
     * @param username
     * @return
     */
    @Override
    public UserDTO getUserByUserName(String username) {
        QueryWrapper<ImUser> imUserQueryWrapper = new QueryWrapper<>();
        imUserQueryWrapper.eq("id", username)
                .or()
                .eq("open_id", username)
                .or()
                .eq("email", username)
                .or()
                .eq("phone_num", username)
                .or()
                .eq("id_card_num", username);
        ImUser imUser = imUserMapper.selectOne(imUserQueryWrapper);
        Assert.notNull(imUser, "未找到的用户!");
        return new UserDTO(imUser.getId().toString(), imUser.getOpenId(), imUser.getUsername(), imUser.getUsername(), imUser.getNickName(), imUser.getPassword(), imUser.getAvatar(), imUser.getMotto(), imUser.getSex(), null, imUser.getPhoneNum(), imUser.getEmail(), imUser.getIdCardNum(), null, imUser.getStatus());
    }


    /**
     * 根据唯一标识搜寻用户/群组信息
     * @ todo 后面优化为缓存查询,以及不使用or及like
     * @param username
     * @return
     */
    @Override
    public List<SearchInfo> search(String username) {
        List<SearchInfo> result = new ArrayList<>();
        // 先查询用户，如果查到则返回
        QueryWrapper<ImUser> imUserQueryWrapper = new QueryWrapper<>();
        imUserQueryWrapper.eq("id", username)
                .or()
                .eq("open_id", username)
                .or()
                .eq("email", username)
                .or()
                .eq("phone_num", username)
                .or()
                .eq("id_card_num", username)
                .or()
                .like("nick_name", username);
        List<ImUser> imUsers = imUserMapper.selectList(imUserQueryWrapper);
        if (CollectionUtils.isNotEmpty(imUsers)) {
            result = imUsers.stream().map(imUser -> new SearchInfo(imUser.getId().toString(), imUser.getNickName(), imUser.getAvatar())).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 获取userId的联系人列表
     * @param userId
     * @return
     */
    @Override
    public List<ImContactDTO> contactList(String userId) {
        List<ImContactDTO> result = new ArrayList<>();
        Map<String, ImFriendBO> entries = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND +userId);
        if (MapUtils.isNotEmpty(entries)) {
            entries.forEach((friendId, imFriendBO)-> {
                result.add(new ImContactDTO(imFriendBO.getFriendUserId(), imFriendBO.getFriendUsername(), imFriendBO.getFriendNickName(), imFriendBO.getFriendAvatar()));
            });
            return result;
        }
        // 查询数据库返回
        List<ImUser> friendContact = imUserMapper.contact(userId);
        if (CollectionUtils.isNotEmpty(friendContact)) {
            friendContact.forEach(friend-> {
                result.add(new ImContactDTO(friend.getId().toString(), friend.getUsername(), friend.getNickName(), friend.getAvatar()));
            });
        }
        return result;
    }

    /**
     * 获取当前登录人的所有群列表， 目前群的列表直接通过数据库查（如果每个人加群都存一份用户和群的关系，会占用很大的内存，所以这里不存redis,读取数据库，后面可以优化存储mogodb等）
     * @param userId
     * @return
     */
    @Override
    public List<ImGroupDTO> groupList(String userId) {
        return imGroupMapper.groupList(userId);
    }

    /**
     * 根据用户主键id获取用户信息
     * @param userId
     * @return
     */
    @Override
    public ImUserDetailDTO getUser(String userId) {
        ImUser imUser = (ImUser) RedisFactory.redisTemplate().opsForValue().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + userId);
        if (imUser == null) {
            imUser = imUserMapper.selectById(userId);
        }
        if (imUser == null) {
            return null;
        }
        return new ImUserDetailDTO(imUser.getId().toString(), imUser.getUsername(), imUser.getNickName(),  imUser.getAvatar(), imUser.getMotto(), imUser.getSex());
    }


    /**
     * 新朋友通知列表
     * @param userId 当前登录人用户id
     * @return
     */

    @Override
    public List<NotifyDTO> newFriendsNotifyList(String userId) {
        List<NotifyDTO> newFriendNotifyDTOList = new ArrayList<>();

        Set<Packet> friendPacketSet = RedisFactory.redisTemplate().opsForZSet().range(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.FRIEND_REQUEST + userId, 0, -1);
        if (friendPacketSet != null) {
            // 记录临时好友的id
            Set<String> userIds = new HashSet<>();
            for (Map.Entry<String, List<Packet>> e : friendPacketSet.stream().collect(Collectors.groupingBy(packet -> {
                Message message = (Message) packet.getMessage();
                String applicationId = IdentityUtil.sortComboIdentity(message.getFrom(), message.getTo());
                return applicationId;
            })).entrySet()) {
                String key = e.getKey();
                List<Packet> applicationPacketList = e.getValue();
                for (Map.Entry<String, List<Packet>> entry : applicationPacketList.stream().collect(Collectors.groupingBy(packet -> {
                    // 返回发起人id
                    Message message = (Message) packet.getMessage();
                    int contentType = message.getContentType();
                    if (MessageContentEnum.FRIEND_AGREE.type() == contentType || MessageContentEnum.FRIEND_REFUSE.type() == contentType) {
                        return message.getTo();
                    }
                    // 默认是添加好友
                    return message.getFrom();
                })).entrySet()) {
                    String applyUserId = entry.getKey();
                    List<Packet> packetList = entry.getValue();
                    // 每个会话list 中的子元素是一个数据信息
                    List<List<Packet>> newFriendsNotifyList = new ArrayList<>();
                    // packetList 是针对申请人申请的多个会话（每个会话以同意或拒绝结束）所作出的所有回复
                    Iterator<Packet> packetIterator = packetList.iterator();
                    List<Packet> itemPacketList = new ArrayList<>();
                    while (packetIterator.hasNext()) {
                        Packet nextPacket = packetIterator.next();
                        Message message = (Message) nextPacket.getMessage();
                        itemPacketList.add(nextPacket);
                        if (MessageContentEnum.FRIEND_AGREE.type() == message.getContentType() || MessageContentEnum.FRIEND_REFUSE.type() == message.getContentType()) {
                            newFriendsNotifyList.add(itemPacketList);
                            itemPacketList = new ArrayList<>();
                        }
                        // 每处理完一个就删掉一个元素
                        packetIterator.remove();
                    }
                    // 做最后兜底
                    if (itemPacketList.size() > 0) {
                        newFriendsNotifyList.add(itemPacketList);
                    }
                    // 遍历并处理值
                    for (List<Packet> packets : newFriendsNotifyList) {// 获取最近一条数据信息，然后进行组装NotifyDto
                        Packet packet = packets.get(packets.size() - 1);
                        Message message = (Message) packet.getMessage();
                        String from = message.getFrom();
                        String to = message.getTo();
                        String userId0 = from;
                        if (userId.equals(from)) {
                            userId0 = to;
                        }
                        int contentType = message.getContentType();
                        Integer handlerStatus = CommonConstant.FRIEND_OR_GROUP_WAIT_FOR_VERIFICATION_HANDLER_STATUS;
                        if (MessageContentEnum.FRIEND_AGREE.type() == contentType) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_AGREE_HANDLER_STATUS;
                        }
                        if (MessageContentEnum.FRIEND_REFUSE.type() == contentType) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_REFUSE_HANDLER_STATUS;
                        }
                        userIds.add(applyUserId);
                        userIds.add(userId0);
                        newFriendNotifyDTOList.add(new NotifyDTO(userId0, IMConstant.USER_TYPE_1, applyUserId, message.getContent(), handlerStatus, message.getCreateTime()));
                    }
                }
            }
            // 处理名称
            if (CollectionUtils.isNotEmpty(userIds)) {
                List<ImUser> imUsers = imUserMapper.selectBatchIds(userIds);
                if (CollectionUtils.isNotEmpty(imUsers)) {
                    newFriendNotifyDTOList = newFriendNotifyDTOList.stream().map(notifyDTO -> {
                        int flag = 0;
                        for (ImUser imUser : imUsers) {
                            if (notifyDTO.getId().equals(imUser.getId().toString())) {
                                notifyDTO.setNickName(imUser.getNickName());
                                notifyDTO.setAvatar(imUser.getAvatar());
                                flag++;
                            }
                            if (notifyDTO.getApplyUserId().equals(imUser.getId().toString())) {
                                notifyDTO.setApplyUserName(imUser.getNickName());
                                flag++;
                            }
                            // 同时满足跳出该次循环
                            if (flag == 2) {
                                break;
                            }
                        }
                        return notifyDTO;
                    }).sorted(Comparator.comparing(NotifyDTO::getCreateTime).reversed()).collect(Collectors.toList());
                }
            }
        }
        // 排序
        return newFriendNotifyDTOList;
    }

    /**
     * 获取用户所属群主或管理员的群通知列表
     * @param userId
     * @return
     */
    @Override
    public List<NotifyDTO> groupNotifyList(String userId) {
        List<NotifyDTO> groupNotifyDTOList = new ArrayList<>();
        Set<String> userIds = new HashSet<>();
        Set<String> groupIds = new HashSet<>();
        // 作为被邀请人，或申请人所处理的通知
        handleGroupNotifyList(userId, userId, userIds, groupIds, groupNotifyDTOList);
        // 获取userId加入群并作为群管理员或群主的所有群信息列表
        List<ImGroupDTO> imGroupDTOS = imGroupMapper.groupListByLeaderOrManager(userId);
        if (CollectionUtils.isNotEmpty(imGroupDTOS)) {
            for (ImGroupDTO imGroupDTO : imGroupDTOS) {
                // 作为管理员或群成员所处理的通知,获取每个群中是否存在需要处理的群请求
                handleGroupNotifyList(userId, imGroupDTO.getId(), userIds, groupIds, groupNotifyDTOList);
            }
        }
        // 处理用户名和群名称
        if (CollectionUtils.isNotEmpty(groupNotifyDTOList) && CollectionUtils.isNotEmpty(userIds)) {
            List<ImUser> imUsers = imUserMapper.selectBatchIds(userIds);
            List<ImGroup> imGroups = imGroupMapper.selectBatchIds(groupIds);
            groupNotifyDTOList = groupNotifyDTOList.stream().map(notifyDTO -> {
                for (ImUser imUser : imUsers) {
                    String imUserId = String.valueOf(imUser.getId());
                    if (imUserId.equals(notifyDTO.getId())) {
                        notifyDTO.setNickName(imUser.getNickName());
                        notifyDTO.setAvatar(imUser.getAvatar());
                    }
                    if (imUserId.equals(notifyDTO.getApplyUserId())) {
                        notifyDTO.setApplyUserName(imUser.getNickName());
                    }
                    if (imUserId.equals(notifyDTO.getInviteUserId())) {
                        notifyDTO.setInviteUserName(imUser.getNickName());
                    }
                    if (imUserId.equals(notifyDTO.getHandlerUserId())) {
                        notifyDTO.setHandlerUsername(imUser.getNickName());
                    }
                }
                for (ImGroup imGroup: imGroups) {
                    String imGroupId = String.valueOf(imGroup.getId());
                    if (imGroupId.equals(notifyDTO.getId())) {
                        notifyDTO.setNickName(imGroup.getGroupName());
                        notifyDTO.setAvatar(imGroup.getGroupAvatar());
                    }
                    if (imGroupId.equals(notifyDTO.getGroupId())) {
                        notifyDTO.setGroupNickName(imGroup.getGroupName());
                        notifyDTO.setGroupAvatar(imGroup.getGroupAvatar());
                    }
                }
                return notifyDTO;
            }).sorted(Comparator.comparing(NotifyDTO::getCreateTime).reversed()).collect(Collectors.toList());
        }
        return groupNotifyDTOList;
    }

    /**
     * 处理群通知集合
     * @param userId
     * @param identity
     * @param userIds
     * @param groupIds
     * @param groupNotifyDTOList
     */
    public static void handleGroupNotifyList(String userId,  String identity, Set<String> userIds, Set<String> groupIds, List<NotifyDTO> groupNotifyDTOList) {
        Set<Packet> packetSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.GROUP_REQUEST + identity, 0, -1);
        // 如果存在则进行处理
        if (CollectionUtils.isNotEmpty(packetSet)) {
            // 根据sessionId进行分组处理
            for (Map.Entry<String, List<Packet>> entry : packetSet.stream().collect(Collectors.groupingBy(packet -> {
                Message message = (Message) packet.getMessage();
                GroupRequestContent groupRequestContent = JSONUtil.toBean(message.getContent(), GroupRequestContent.class);
                return groupRequestContent.getSessionId();
            })).entrySet()) {
                List<Packet> packetList = entry.getValue();
                // 获取每个会话中最近的一条消息，可以推断出该会话的所处的状态,这里有个规则就是，只能有一个人来处理，不能多人同意或多人拒绝
                Packet packet = packetList.get(0);
                Message message = (Message) packet.getMessage();
                String from = message.getFrom();
                int contentType = message.getContentType();
                GroupRequestContent groupRequestContent = JSONUtil.toBean(message.getContent(), GroupRequestContent.class);
                String groupId = groupRequestContent.getGroupId();
                // 需要显示的人
                String id = groupRequestContent.getIdentity();
                // 申请人
                String applyUserId = null;
                // 邀请人
                String inviteUserId = null;
                //被邀请人
                String invitedUserId = null;
                // 由于只能请求只能有一个人对其进行处理，所以处理人一般不会存在覆盖
                // 处理人
                String handlerUserId = null;
                Integer handlerStatus = CommonConstant.FRIEND_OR_GROUP_WAIT_FOR_VERIFICATION_HANDLER_STATUS;
                if (MessageContentEnum.GROUP_JOIN.type() == contentType) {
                    applyUserId = groupRequestContent.getIdentity();
                    if (userId.equals(applyUserId)) {
                        id = groupId;
                    }else {
                        id = applyUserId;
                    }
                }
                // 邀请和主动申请后管理员的处理都会走这里
                if (MessageContentEnum.GROUP_AGREE.type() == contentType || MessageContentEnum.GROUP_REFUSE.type() == contentType) {
                    if (CollectionUtils.isNotEmpty(groupRequestContent.getInvitedUserIdList())) {
                        // 邀请的处理
                        inviteUserId = groupRequestContent.getIdentity();
                        invitedUserId = groupRequestContent.getInvitedUserIdList().get(0);
                        handlerUserId = from;
                        if (userId.equals(from)) {
                            id = invitedUserId;
                        }else {
                            id = inviteUserId;
                        }
                        if (MessageContentEnum.GROUP_AGREE.type() == contentType) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_AGREE_HANDLER_STATUS;
                        }
                        if (MessageContentEnum.GROUP_REFUSE.type() == contentType) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_REFUSE_HANDLER_STATUS;
                        }




                    }else {
                        applyUserId = groupRequestContent.getIdentity();
                        handlerUserId = from;
                        if (MessageContentEnum.GROUP_AGREE.type() == contentType) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_AGREE_HANDLER_STATUS;
                        } else {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_REFUSE_HANDLER_STATUS;
                        }
                    }

                }
                if (MessageContentEnum.GROUP_INVITE_JOIN.type() == contentType || MessageContentEnum.GROUP_INVITE_AGREE.type() == contentType || MessageContentEnum.GROUP_INVITE_REFUSE.type() == contentType) {
                    inviteUserId = groupRequestContent.getIdentity();
                    invitedUserId = userId;
                    if (MessageContentEnum.GROUP_INVITE_AGREE.type() == contentType) {
                        invitedUserId = groupRequestContent.getInvitedUserIdList().get(0);
                        handlerUserId = from;
                        handlerStatus = CommonConstant.GROUP_INVITE_AGREE_HANDLER_STATUS;
                        // 如果该邀请人当时是群主或管理员邀请的，则是自动通过已同意
                        if (IMConstant.GROUP_LEADER_OR_MANAGER.equals(groupRequestContent.getExtra())) {
                            handlerStatus = CommonConstant.FRIEND_OR_GROUP_AGREE_HANDLER_STATUS;
                        }
                        if (userId.equals(from)) {
                            id = inviteUserId;
                        }else {
                            id = from;
                        }
                    }
                    if (MessageContentEnum.GROUP_INVITE_REFUSE.type() == contentType) {
                        invitedUserId = groupRequestContent.getInvitedUserIdList().get(0);
                        handlerUserId = from;
                        handlerStatus = CommonConstant.FRIEND_OR_GROUP_REFUSE_HANDLER_STATUS;
                        if (userId.equals(from)) {
                            id = inviteUserId;
                        }else {
                            id = from;
                        }
                    }
                }
                userIds.add(id);
                userIds.add(applyUserId);
                userIds.add(inviteUserId);
                userIds.add(handlerUserId);
                groupIds.add(groupId);
                groupNotifyDTOList.add(new NotifyDTO(id, groupId, applyUserId, inviteUserId, invitedUserId, groupRequestContent.getSessionId(), handlerUserId, handlerStatus, IMConstant.GROUP_TYPE_2, contentType, groupRequestContent.getData(), message.getCreateTime()));
            }
        }

    }
    /**
     * 判断to 是否是userId 的好友，true-存在好友，false-不存在好友
     * @param userId
     * @param to
     * @return
     */
    @Override
    public boolean existFriend(String userId, String to) {
        ImFriendBO imFriendBO = (ImFriendBO) RedisFactory.redisTemplate().opsForHash().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND + userId, to);
        // 已经是好友了
        if (imFriendBO != null) {
            return true;
        }
        // 从数据库中查询
        QueryWrapper<ImFriend> imFriendQueryWrapper = new QueryWrapper<>();
        imFriendQueryWrapper.eq("user_id", userId).eq("friend_user_id", to);
        ImFriend imFriend = imFriendMapper.selectOne(imFriendQueryWrapper);
        return imFriend != null;
    }

    /**
     * 屏蔽好友
     * @param userId
     * @param friendId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public int shieldFriend(String userId, String friendId, Integer isShield) {
        QueryWrapper<ImFriend> imFriendQueryWrapper = new QueryWrapper<>();
        imFriendQueryWrapper.eq("user_id", userId).eq("friend_user_id", friendId);
        ImFriend imFriend = imFriendMapper.selectOne(imFriendQueryWrapper);
        if (imFriend != null && (IMConstant.SHIELD.equals(isShield) || IMConstant.NOT_SHIELD.equals(isShield))) {
            imFriend.setIsShield(isShield);
            imFriendMapper.updateById(imFriend);
            RedisFactory.redisTemplate().opsForHash().delete(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND + userId, friendId);
        }
        // 获取联系人信息
        return 1;
    }

    /**
     * 将用户加入黑名单
     * @param loginUserId
     * @param userId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public int userJoinBlacklist(String loginUserId, String userId, Integer join) {
        if (IMConstant.JOIN_BLACKLIST.equals(join)) {
            String nowDateTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            ImBlacklist imBlacklist = new ImBlacklist(Long.valueOf(loginUserId), Long.valueOf(userId), IMConstant.USER_TYPE_1 , nowDateTime);
            imBlacklistMapper.insert(imBlacklist);
        }
        if (IMConstant.NOT_JOIN_BLACKLIST.equals(join)) {
            QueryWrapper<ImBlacklist> imBlacklistQueryWrapper = new QueryWrapper<>();
            imBlacklistQueryWrapper.eq("identity", loginUserId).eq("user_id",userId).eq("identity_type", IMConstant.USER_TYPE_1);
            ImBlacklist imBlacklist = imBlacklistMapper.selectOne(imBlacklistQueryWrapper);
            if (imBlacklist != null) {
                imBlacklistMapper.deleteById(imBlacklist);
            }
        }
        return 1;
    }

    /**
     * 删除好友
     * @param userId
     * @param friendId
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public int deleteFriend(String userId, String friendId) {
        QueryWrapper<ImFriend> imFriendQueryWrapper = new QueryWrapper<>();
        imFriendQueryWrapper.eq("user_id", userId).eq("friend_user_id", friendId);
        ImFriend imFriend = imFriendMapper.selectOne(imFriendQueryWrapper);
        if (imFriend != null) {
            imFriendMapper.deleteById(imFriend);
            RedisFactory.redisTemplate().opsForHash().delete(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND + userId, friendId);
        }
        QueryWrapper<ImFriend> imFriendQueryWrapper0 = new QueryWrapper<>();
        imFriendQueryWrapper0.eq("user_id", friendId).eq("friend_user_id", userId);
        ImFriend imFriend0 = imFriendMapper.selectOne(imFriendQueryWrapper0);
        if (imFriend0 != null) {
            imFriendMapper.deleteById(imFriend0);
            RedisFactory.redisTemplate().opsForHash().delete(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND + friendId, userId);
        }
        return 1;
    }

    /**
     * 获取userId 的好友 friendId 的相关用户信息
     * @param userId
     * @param friendId
     * @return
     */
    @Override
    public ImFriendDTO getFriend(String userId, String friendId) {

        ImUser imUser = (ImUser) RedisFactory.redisTemplate().opsForValue().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + friendId);
        if (imUser == null) {
            imUser = imUserMapper.selectById(friendId);
        }
        if (imUser == null) {
            return null;
        }
        ImFriendDTO friendDTO = new ImFriendDTO(imUser.getId(), imUser.getUsername(), imUser.getNickName(), imUser.getAvatar(), imUser.getMotto(), imUser.getSex(), 0);
        ImFriendBO imFriendBO = (ImFriendBO) RedisFactory.redisTemplate().opsForHash().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.CONTACT + CacheConstant.FRIEND + userId, friendId);
        if (imFriendBO == null) {
            QueryWrapper<ImFriend> friendQueryWrapper = new QueryWrapper<>();
            friendQueryWrapper.eq("user_id", userId).eq("friend_user_id", friendId);
            ImFriend friend = imFriendMapper.selectOne(friendQueryWrapper);
            if (friend != null) {
                friendDTO.setNickName(friend.getFriendNickName());
                friendDTO.setIsShield(friend.getIsShield());
                friendDTO.setExistFriend(1);
            }
        }else {
            friendDTO.setNickName(imFriendBO.getFriendNickName());
            friendDTO.setIsShield(imFriendBO.getFriendIsShield());
            friendDTO.setExistFriend(1);
        }
        // 获取黑名单
        ImBlacklistBO imBlacklistBO = (ImBlacklistBO) RedisFactory.redisTemplate().opsForHash().get(CacheConstant.OUYUNC + CacheConstant.IM + CacheConstant.BLACK_LIST + CacheConstant.USER + userId, friendId);
        if (imBlacklistBO == null) {
            QueryWrapper<ImBlacklist> imBlacklistQueryWrapper = new QueryWrapper<>();
            imBlacklistQueryWrapper.eq("identity", userId).eq("user_id",friendId).eq("identity_type", IMConstant.USER_TYPE_1);
            ImBlacklist imBlacklist = imBlacklistMapper.selectOne(imBlacklistQueryWrapper);
            if (imBlacklist != null) {
                friendDTO.setExistBlacklist(1);
            }
        }else {
            friendDTO.setExistBlacklist(1);
        }
        Map friendLoginInfoMap = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.LOGIN + friendId);
        if (MapUtils.isNotEmpty(friendLoginInfoMap)) {
            friendDTO.setOnline(1);
        }

        return friendDTO;
    }

    /**
     * 判断用户identity是否存已经在群group中
     * @param identity
     * @param groupId
     * @return
     */
    @Override
    public boolean existGroup(String identity, String groupId) {
        ImGroupUserBO imGroupUserBO = (ImGroupUserBO) RedisFactory.redisTemplate().opsForHash().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.GROUP + groupId + CacheConstant.MEMBERS, identity);
        if (imGroupUserBO != null) {
            return true;
        }
        QueryWrapper<ImGroupUser> imGroupUserQueryWrapper = new QueryWrapper<>();
        imGroupUserQueryWrapper.eq("user_id", identity).eq("group_id", groupId);
        ImGroupUser imGroupUser = imGroupUserMapper.selectOne(imGroupUserQueryWrapper);
        return imGroupUser != null;
    }

    /**
     * 获取群请求中该sessionId最后一个消息包的处理状态
     * @param sessionId
     * @param groupId
     * @return
     */
    @Override
    public boolean sessionHandler(String sessionId, String groupId) {
        Set<Packet> groupPacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.GROUP_REQUEST + groupId, 0, -1);
        boolean isHandled = false;
        if (groupPacketSet == null) {
            return isHandled;
        }
        for (Map.Entry<String, List<Packet>> entry : groupPacketSet.stream().collect(Collectors.groupingBy(packet -> {
            Message message = (Message) packet.getMessage();
            GroupRequestContent groupRequestContent = JSONUtil.toBean(message.getContent(), GroupRequestContent.class);
            return groupRequestContent.getSessionId();
        })).entrySet()) {
            String sessionId0 = entry.getKey();
            List<Packet> packetList = entry.getValue();
            if (sessionId.equals(sessionId0)) {
                // 获取该session会话中的最近一个消息处理包
                Packet packet = packetList.get(0);
                Message message = (Message) packet.getMessage();
                int contentType = message.getContentType();
                if (MessageContentEnum.GROUP_AGREE.type() == contentType || MessageContentEnum.GROUP_REFUSE.type() == contentType) {
                    isHandled = true;
                    continue;
                }
            }
        }
        return isHandled;
    }

    /**
     * 根据群id获取群成员列表
     * @param groupId
     * @return
     */
    @Override
    public List<ImContactDTO> groupMembers(String groupId) {
        List<ImContactDTO> imContactDTOList = new ArrayList<>();
        Map<String, ImGroupUserBO> imGroupUserBOMap = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.GROUP + groupId + CacheConstant.MEMBERS);
        if (MapUtils.isEmpty(imGroupUserBOMap)) {
            // 从数据库查询
            List<ImGroupUserBO> imGroupUsers = imGroupUserMapper.getGroupUserList(groupId);
            if (imGroupUsers == null) {
                return imContactDTOList;
            }
            Map<String, ImGroupUserBO> groupUserBOMap = new HashMap<>();
            List<ImContactDTO> collect = imGroupUsers.stream().map(imGroupUserBO -> {
                groupUserBOMap.put(imGroupUserBO.getUserId(), imGroupUserBO);
                return new ImContactDTO(imGroupUserBO.getUserId(), imGroupUserBO.getUsername(), imGroupUserBO.getNickName(), imGroupUserBO.getAvatar(), imGroupUserBO.getIsManager(), imGroupUserBO.getIsLeader());
            }).collect(Collectors.toList());
            RedisFactory.redisTemplate().opsForHash().putAll(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.GROUP + groupId + CacheConstant.MEMBERS, groupUserBOMap);
            return collect;
        }
        imContactDTOList = imGroupUserBOMap.entrySet().stream().map(mapItem->{
            ImGroupUserBO imGroupUserBO = mapItem.getValue();
            return new ImContactDTO(imGroupUserBO.getUserId(), imGroupUserBO.getUsername(), imGroupUserBO.getNickName(), imGroupUserBO.getAvatar(),imGroupUserBO.getIsManager(), imGroupUserBO.getIsLeader());
        }).collect(Collectors.toList());
        return imContactDTOList;
    }

    /**
     * 更新好友或群组在本地的好友昵称备注 @todo 这里只修改了数据库中的数据，缓存中存在的额还是老数据，后面进行优化修改
     * @param identity
     * @param nicknameRemark
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public int updateNickName(String identity, String nicknameRemark, Integer userType,Integer type, String userId) {
        if (IMConstant.USER_TYPE_1.equals(userType)) {
            QueryWrapper<ImFriend> imFriendQueryWrapper = new QueryWrapper<>();
            imFriendQueryWrapper.eq("user_id", userId).eq("friend_user_id", identity);
            ImFriend imFriend = imFriendMapper.selectOne(imFriendQueryWrapper);
            if (imFriend != null) {
                imFriend.setFriendNickName(nicknameRemark);
                return imFriendMapper.updateById(imFriend);
            }
        }
        if (IMConstant.GROUP_TYPE_2.equals(userType)) {
            QueryWrapper<ImGroupUser> imGroupUserQueryWrapper = new QueryWrapper<>();
            imGroupUserQueryWrapper.eq("group_id", identity).eq("user_id", userId);
            ImGroupUser imGroupUser = imGroupUserMapper.selectOne(imGroupUserQueryWrapper);
            if (imGroupUser  != null) {
                if (CommonConstant.UPDATE_GROUP_NICKNAME.equals(type)) {
                    imGroupUser.setGroupNickName(nicknameRemark);
                }
                if (CommonConstant.UPDATE_GROUP_USER_NICKNAME.equals(type)) {
                    imGroupUser.setUserNickName(nicknameRemark);
                }
                return imGroupUserMapper.updateById(imGroupUser);
            }
        }
        return 0;
    }

    /**
     * 获取当亲登录人临时聊天联系人列表，一般情况下，在app中会缓存该数据
     * @param userId
     * @return
     */
    @Override
    public List<ImTempChatContactDTO> tempChatList(String userId) {
        List<ImTempChatContactDTO> result = new ArrayList<>();
        // 从缓存中获取临时聊天列表，
        Map<String, ImTempChatDTO> entries = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CommonConstant.TEMP_CHAT_CONTACT + userId);
        if (MapUtils.isNotEmpty(entries)) {
            List<Packet> packetList = new ArrayList<>();
            // 从我的收件箱和发件箱获取最最近一条的数据，一般收件箱和发件箱只存最近30天的数据，如果30天数据少于100条，则保留100条数据，更多历史数据请通过数据库查询、
            Set<Packet> sendPacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.SEND + userId, 0, -1);
            Set<Packet> receivePacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.RECEIVE + userId, 0, -1);
            // 如果是私聊，通过这两个数据筛选出属于连个人会话的最后一条数据
            if (CollectionUtils.isNotEmpty(sendPacketSet)) {
                if (CollectionUtils.isNotEmpty(receivePacketSet)) {
                    sendPacketSet.addAll(receivePacketSet);

                }
            }else {
                if (CollectionUtils.isNotEmpty(receivePacketSet)) {
                    sendPacketSet = receivePacketSet;
                }
            }
            for (Map.Entry<String, ImTempChatDTO> entry : entries.entrySet()) {
                ImTempChatDTO value = entry.getValue();
                ImMessageDTO imMessageDTO = new ImMessageDTO();
                Integer online = 0;
                if (IMConstant.USER_TYPE_1.equals(value.getType())) {
                    // 判断好友是否在线
                    Map<String, LoginUserInfo> loginUserInfoMap = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.LOGIN + value.getId());
                    if (MapUtils.isNotEmpty(loginUserInfoMap)) {
                        online = 1;
                    }
                    // 进行排序
                    packetList = sendPacketSet.parallelStream().filter(packet -> {
                        Message message = (Message) packet.getMessage();
                        if (packet.getMessageType() == MessageEnum.IM_PRIVATE_CHAT.getValue() && (    (message.getFrom().equals(userId) && message.getTo().equals(value.getId())) || message.getFrom().equals(value.getId()) && message.getTo().equals(userId))) {
                            return true;
                        }
                        return false;
                    }).sorted(Comparator.comparing(packet -> {
                        Message message = (Message) packet.getMessage();
                        return message;
                    }, (o1,o2)->{
                        if (o1.getCreateTime() > o2.getCreateTime()) {
                            return -1;
                        }
                        if (o1.getCreateTime() < o2.getCreateTime()) {
                            return 1;
                        }
                        return 0;
                    })).collect(Collectors.toList());
                    Iterator<Packet> iterator = packetList.iterator();
                    while (iterator.hasNext()) {
                        Packet packet = iterator.next();
                        Message message = (Message) packet.getMessage();
                        if ((message.getFrom().equals(userId) && message.getTo().equals(value.getId()) || (message.getFrom().equals(value.getId()) && message.getTo().equals(userId)) && MessageEnum.IM_PRIVATE_CHAT.getValue() == packet.getMessageType() && (MessageContentEnum.CHAT_TEXT_CONTENT.type() == message.getContentType() || MessageContentEnum.CHAT_ATTACHMENT_CONTENT.type() == message.getContentType() || MessageContentEnum.CHAT_NAME_CARD.type() == message.getContentType()))) {
                            imMessageDTO.setId(String.valueOf(packet.getPacketId()));
                            imMessageDTO.setContentType(message.getContentType());
                            imMessageDTO.setContent(message.getContent());
                            imMessageDTO.setCreateTime(message.getCreateTime());
                            break;
                        }
                    }
                }
                // 如果是群组，则从群组收件箱中获取消息即可，因为群组消息只存一份
                if (IMConstant.GROUP_TYPE_2.equals(value.getType())) {
                    Set<Packet> groupReceivePacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.RECEIVE + value.getId(), 0, -1);
                    if (CollectionUtils.isNotEmpty(groupReceivePacketSet)) {
                        Iterator<Packet> iterator = groupReceivePacketSet.iterator();
                        Packet packet = iterator.next();
                        Message message = (Message) packet.getMessage();
                        ImUserDetailDTO user = getUser(message.getFrom());
                        imMessageDTO.setId(String.valueOf(packet.getPacketId()));
                        imMessageDTO.setFrom(user.getNickName());
                        imMessageDTO.setContentType(message.getContentType());
                        imMessageDTO.setContent(message.getContent());
                        imMessageDTO.setCreateTime(message.getCreateTime());
                    }
                }
                ImTempChatContactDTO imTempChatContactDTO = new ImTempChatContactDTO(value.getId(), value.getUsername(), value.getNickName(), value.getAvatar(), online, value.getType(), value.getUnreadMsgCount(), imMessageDTO);
                result.add(imTempChatContactDTO);
            }
        }
        //按提交时间降序 --Lamdba表达式
        Collections.sort(result, (a, b) -> {
            if (b.getLastMsg().getCreateTime() == null || a.getLastMsg().getCreateTime() == null) {
                return b.getId().compareTo(a.getId());
            }else {
                return b.getLastMsg().getCreateTime().compareTo(a.getLastMsg().getCreateTime());
            }
        });
        // 获取每个临时会话的最近一条消息
        return result;
    }


    /**
     * 添加临时聊天
     * @param from
     * @param to 个人id/群组id
     * @param userType
     * @return
     */
    @Override
    public boolean addTempChat(String from, String to, Integer userType) {
        ImUserDetailDTO fromUser = getUser(from);
        ImTempChatDTO imTempChatDTO = new ImTempChatDTO(from, fromUser.getUsername(), fromUser.getNickName(), fromUser.getAvatar(), null, null);
        imTempChatDTO.setType(userType);
        if (IMConstant.USER_TYPE_1.equals(userType)) {
            RedisFactory.redisTemplate().opsForHash().putIfAbsent(CacheConstant.OUYUNC + CacheConstant.IM_USER + CommonConstant.TEMP_CHAT_CONTACT + to, from, imTempChatDTO);
            ImUserDetailDTO toUser = getUser(to);
            imTempChatDTO.setId(to);
            imTempChatDTO.setUsername(toUser.getUsername());
            imTempChatDTO.setNickName(toUser.getNickName());
            imTempChatDTO.setAvatar(toUser.getAvatar());
            RedisFactory.redisTemplate().opsForHash().putIfAbsent(CacheConstant.OUYUNC + CacheConstant.IM_USER + CommonConstant.TEMP_CHAT_CONTACT + from, to, imTempChatDTO);
        }
        if (IMConstant.GROUP_TYPE_2.equals(userType)) {
            ImGroup imGroup = imGroupMapper.selectById(to);
            imTempChatDTO.setId(to);
            imTempChatDTO.setUsername(imGroup.getGroupName());
            imTempChatDTO.setNickName(imGroup.getGroupName());
            imTempChatDTO.setAvatar(imGroup.getGroupAvatar());
            RedisFactory.redisTemplate().opsForHash().putIfAbsent(CacheConstant.OUYUNC + CacheConstant.IM_USER + CommonConstant.TEMP_CHAT_CONTACT + from, to, imTempChatDTO);
        }
        return true;
    }

    /**
     * 获取联系人在线状态, 这个接口会调用很多，建议进行优化并单独提供服务
     * @param userId
     * @return
     */
    @Override
    public List<ImTempChatContactDTO> contactOnline(String userId) {
        List<ImTempChatContactDTO> result = new ArrayList<>();
        List<ImContactDTO> imContactDTOList = contactList(userId);
        if (CollectionUtils.isNotEmpty(imContactDTOList)) {
            imContactDTOList.forEach(imContactDTO -> {
                ImTempChatContactDTO imTempChatContactDTO = new ImTempChatContactDTO(imContactDTO.getId(), imContactDTO.getUsername(), imContactDTO.getNickName(), imContactDTO.getAvatar(), OnlineEnum.OFFLINE.ordinal(), IMConstant.USER_TYPE_1, null, null);
                Map<String, LoginUserInfo> loginUserInfoMap = RedisFactory.redisTemplate().opsForHash().entries(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.LOGIN + imContactDTO.getId());
                if (MapUtils.isNotEmpty(loginUserInfoMap)) {
                    imTempChatContactDTO.setOnline(OnlineEnum.ONLINE.ordinal());
                }
                result.add(imTempChatContactDTO);
            });
        }
        return result;
    }

    /**
     * 聊天历史记录
     * @param userId
     * @param identity
     * @param userType
     * @return
     */
    @Override
    public IPage<HistoryRecordDTO> chatHistoryRecord(String userId, String identity, Integer userType,Integer pageNum, Integer pageSize,Integer total) {
        IPage<HistoryRecordDTO> page =new Page<>(pageNum, pageSize);
        Integer offset = (pageNum-1)*pageSize;


        List<HistoryRecordDTO> historyRecordDTOList = new ArrayList<>();
        // 个人
        if (IMConstant.USER_TYPE_1.equals(userType)) {
            Set<Packet> sendPacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.SEND + userId, 0, -1);
            Set<Packet> receivePacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.RECEIVE + userId, 0, -1);
            if (CollectionUtils.isNotEmpty(sendPacketSet)) {
                if (CollectionUtils.isNotEmpty(receivePacketSet)) {
                    sendPacketSet.addAll(receivePacketSet);
                }
            }else {
                if (CollectionUtils.isNotEmpty(receivePacketSet)) {
                    sendPacketSet = receivePacketSet;
                }
            }
            if (CollectionUtils.isEmpty(sendPacketSet)) {
                page.setTotal(0);
                page.setRecords(historyRecordDTOList);
                return page;
            }

            List<HistoryRecordDTO> historyRecordDTOS = sendPacketSet.parallelStream().filter(packet -> {
                Message message = (Message) packet.getMessage();
                if (packet.getMessageType() == MessageEnum.IM_PRIVATE_CHAT.getValue() && ((message.getFrom().equals(userId) && message.getTo().equals(identity)) || message.getFrom().equals(identity) && message.getTo().equals(userId))) {
                    return true;
                }
                return false;
            }).sorted(Comparator.comparing(packet -> {
                Message message = (Message) packet.getMessage();
                return message;
            }, (o1, o2) -> {
                if (o1.getCreateTime() > o2.getCreateTime()) {
                    return -1;
                }
                if (o1.getCreateTime() < o2.getCreateTime()) {
                    return 1;
                }
                return 0;
            })).map(packet -> {
                Message message = (Message) packet.getMessage();
                int contentType = message.getContentType();
                String content = message.getContent();
                ImUserDetailDTO user = getUser(message.getFrom());
                ImContactDTO imContactDTO = new ImContactDTO(user.getId(), user.getUsername(), user.getNickName(), user.getAvatar());
                HistoryRecordDTO historyRecordDTO = new HistoryRecordDTO(String.valueOf(packet.getPacketId()), 2, message.getContentType(), content, message.getCreateTime(), imContactDTO);
                if (MessageContentEnum.CHAT_TEXT_CONTENT.type() != contentType && MessageContentEnum.CHAT_VOICE_CALL_RECORD_CONTENT.type() != contentType && MessageContentEnum.CHAT_VIDEO_CALL_RECORD_CONTENT.type() != contentType) {
                    JSONObject contentObj = JSONUtil.parseObj(content);
                    historyRecordDTO.setContent(contentObj);
                }
                return historyRecordDTO;
            }).collect(Collectors.toList());
            if  (total != 0 && pageNum > 1) {
                offset = offset + (historyRecordDTOS.size() - total);
            }
            historyRecordDTOList = historyRecordDTOS.parallelStream().skip(offset).limit(pageSize).collect(Collectors.toList());
            page.setTotal(historyRecordDTOS.size());
            if (total != 0) {
                page.setTotal(total);
            }
            page.setRecords(historyRecordDTOList);
        }
        // 群组聊天记录
        if (IMConstant.GROUP_TYPE_2.equals(userType)) {
            Set<Packet> groupReceivePacketSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.RECEIVE + identity, 0, -1);
            if (CollectionUtils.isEmpty(groupReceivePacketSet)) {
                return page;
            }
            if  (total != 0 && pageNum > 1) {
                offset = offset + (groupReceivePacketSet.size() - total);
            }
            historyRecordDTOList = groupReceivePacketSet.parallelStream().filter(packet -> packet.getMessageType() == MessageEnum.IM_GROUP_CHAT.getValue()).map(packet -> {
                Message message = (Message) packet.getMessage();
                int contentType = message.getContentType();
                String content = message.getContent();
                ImUserDetailDTO user = getUser(message.getFrom());
                ImContactDTO imContactDTO = new ImContactDTO(user.getId(), user.getUsername(),user.getNickName(), user.getAvatar());
                HistoryRecordDTO historyRecordDTO = new HistoryRecordDTO(String.valueOf(packet.getPacketId()), 2, message.getContentType(), content, message.getCreateTime(), imContactDTO);
                if (MessageContentEnum.CHAT_TEXT_CONTENT.type() != contentType && MessageContentEnum.CHAT_VOICE_CALL_RECORD_CONTENT.type() != contentType && MessageContentEnum.CHAT_VIDEO_CALL_RECORD_CONTENT.type() != contentType) {
                    JSONObject contentObj = JSONUtil.parseObj(content);
                    historyRecordDTO.setContent(contentObj);
                }
                return historyRecordDTO;
            }).skip(offset).limit(pageSize).collect(Collectors.toList());
            page.setTotal(historyRecordDTOList.size());
            if (total != 0) {
                page.setTotal(total);
            }
            page.setRecords(historyRecordDTOList);
        }
        return page;
    }

    /**
     * 删除当前登录人的identiry 临时联系人
     * @param userId
     * @param identity
     * @return
     */
    @Override
    public boolean deleteTempChat(String userId, String identity) {
        RedisFactory.redisTemplate().opsForHash().delete(CacheConstant.OUYUNC + CacheConstant.IM_USER + CommonConstant.TEMP_CHAT_CONTACT + userId, identity);
        return true;
    }

    /**
     * 获取群成员信息
     * @param groupId
     * @param userId
     * @return
     */
    @Override
    public ImContactDTO groupMember(String groupId, String userId) {
        ImGroupUserBO imGroupUserBO = (ImGroupUserBO) RedisFactory.redisTemplate().opsForHash().get(CacheConstant.OUYUNC + CacheConstant.IM_USER + CacheConstant.GROUP + groupId + CacheConstant.MEMBERS, userId);
        if (imGroupUserBO == null) {
            imGroupUserBO = imGroupUserMapper.getGroupUser(groupId, userId);
        }
        if (imGroupUserBO == null) {
            return null;
        }
        return new ImContactDTO(imGroupUserBO.getUserId(), imGroupUserBO.getUsername(), imGroupUserBO.getNickName(), imGroupUserBO.getAvatar(), imGroupUserBO.getIsManager(), imGroupUserBO.getIsLeader());
    }


    /**
     * 拉取当前登录人离线未读消息
     * @param userId
     * @return
     */
    @Override
    public List<OfflineContent> pullOfflineUnreadMessage(String userId) {
        List<OfflineContent> unreadContentList = new ArrayList<>();
        Set<Packet<Message>> packetSetResult = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.OFFLINE + userId, 0, -1);
        if (CollectionUtils.isNotEmpty(packetSetResult)) {
                packetSetResult.stream().collect(Collectors.groupingBy(packet -> packet.getMessage().getFrom())).forEach((from, packetList) -> {
                    if (CollectionUtils.isNotEmpty(packetList)) {
                        packetList.stream().collect(Collectors.groupingBy(Packet::getMessageType)).forEach((messageType, messageTypePackets) -> {
                            MessageEnum prototype = MessageEnum.prototype(messageType);
                            if (MessageEnum.IM_PRIVATE_CHAT.equals(prototype)) {
                                List<Packet<Message>> lastPackets = new ArrayList<>();
                                lastPackets.add(messageTypePackets.get(0));
                                unreadContentList.add(new OfflineContent(from, IMConstant.USER_TYPE_1, messageTypePackets.size(), lastPackets));
                            }
                            if (MessageEnum.IM_GROUP_CHAT.equals(prototype) && CollectionUtils.isNotEmpty(messageTypePackets)) {
                                messageTypePackets.stream().collect(Collectors.groupingBy(packet -> packet.getMessage().getTo())).forEach((to, groupMessagePackets) -> {
                                    List<Packet<Message>> lastPackets = new ArrayList<>();
                                    lastPackets.add(groupMessagePackets.get(0));
                                    unreadContentList.add(new OfflineContent(to, IMConstant.GROUP_TYPE_2, groupMessagePackets.size(), lastPackets));
                                });
                            }
                        });
                    }
                });
            }
        return unreadContentList;
    }

    /**
     * 分页拉取离线消息
     * @param userId
     * @param offlineContent
     * @return
     */
    @Override
    public OfflineContent pullOfflineMessage(String userId, OfflineContent offlineContent) {
        List<Packet<Message>> result = new ArrayList<>();
        // 判断是按需来取还是全量拉取
        List<Packet<Message>> packetList = offlineContent.getPacketList();
        // 如果传过来的消息id不为空，则可能是第N次拉取，从离线消息中删除消息
        if (CollectionUtils.isNotEmpty(packetList)) {
            for (Packet<Message> packet : packetList) {
                RedisFactory.redisTemplate().opsForZSet().remove(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.OFFLINE + userId, packet);
            }
        }
        // 全量顺序拉取，一次拉取pullSize 大小的消息
        if (StringUtils.isNotBlank(offlineContent.getIdentity()) && (IMConstant.USER_TYPE_1.equals(offlineContent.getIdentityType()) || IMConstant.GROUP_TYPE_2.equals(offlineContent.getIdentityType()))) {
            // 按需拉取,先查出所有，然后过滤前几条给客户端
            Set<Packet<Message>> packetAllSet = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.OFFLINE + userId, 0, -1);
            if (CollectionUtils.isNotEmpty(packetAllSet)) {
                Iterator<Packet<Message>> iterator = packetAllSet.iterator();
                if (IMConstant.USER_TYPE_1.equals(offlineContent.getIdentityType())) {
                    while (iterator.hasNext()) {
                        Packet<Message> packet = iterator.next();
                        if (result.size() >= offlineContent.getCount()) {
                            break;
                        }
                        if (offlineContent.getIdentity().equals(packet.getMessage().getFrom()) && MessageEnum.IM_PRIVATE_CHAT.getValue() == packet.getMessageType()) {
                            result.add(packet);
                        }
                    }
                }
                if (IMConstant.GROUP_TYPE_2.equals(offlineContent.getIdentityType())) {
                    while (iterator.hasNext()) {
                        Packet<Message> packet = iterator.next();
                        if (result.size() >= offlineContent.getCount()) {
                            break;
                        }
                        if (offlineContent.getIdentity().equals(packet.getMessage().getTo()) && MessageEnum.IM_GROUP_CHAT.getValue() == packet.getMessageType()) {
                            result.add(packet);
                        }
                    }
                }
            }
        } else {
            // 全量分页拉取
            Set<Packet<Message>> packetSetResult = RedisFactory.redisTemplate().opsForZSet().reverseRange(CacheConstant.OUYUNC + CacheConstant.IM_MESSAGE + CacheConstant.OFFLINE + userId, 0, offlineContent.getCount() - 1);
            if (CollectionUtils.isNotEmpty(packetSetResult)) {
                Iterator<Packet<Message>> iterator = packetSetResult.iterator();
                while (iterator.hasNext()) {
                    result.add(iterator.next());
                }
            }
        }
        offlineContent.setPacketList(result);
        return offlineContent;
    }



}
